package models

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/beego/beego/v2/client/orm"
	beego "github.com/beego/beego/v2/server/web"
	"github.com/dgrijalva/jwt-go"
	"github.com/gomodule/redigo/redis"
)

type Classmates struct {
	Id        int     `orm:"column(id);auto"`
	Name      string  `orm:"column(name);size(45);null"`
	Sn        string  `orm:"column(sn);size(45);null"`
	Sex       string  `orm:"column(sex);size(5);null"`
	Tel       string  `orm:"column(tel);size(45);null"`
	Email     string  `orm:"column(email);size(45);null"`
	Grade     int     `orm:"column(grade);null" description:"年级"`
	Classname string  `orm:"column(classname);size(45);null"`
	Ip1       string  `orm:"column(ip1);size(45);null"`
	Comments  string  `orm:"column(comments);size(105);null"`
	Status    string  `orm:"column(status);size(50);null"`
	Xueji     string  `orm:"column(xueji);size(50);null"`
	Ip2       string  `orm:"column(ip2);size(45);null"`
	Ip3       string  `orm:"column(ip3);size(45);null"`
	Pswd      string  `orm:"column(pswd);size(45);null"`
	Gitee     string  `orm:"column(gitee);size(85);null"`
	Account   float64 `orm:"column(account);null;digits(20);decimals(2)" description:"账号"`
	Face      string  `orm:"column(face);size(185);null"`
}

func (t *Classmates) TableName() string {
	return "classmates"
}

var aliyunKey string

func init() {
	var err error
	aliyunKey, err = beego.AppConfig.String("aliyunAPIKey")
	if err != nil {
		fmt.Println("获取阿里云的key报错，请检查配置文件")
		return
	}
	orm.RegisterModel(new(Classmates))
}

// AddClassmates insert a new Classmates into database and returns
// last inserted Id on success.
func AddClassmates(m *Classmates) (id int64, err error) {
	o := orm.NewOrm()
	id, err = o.Insert(m)
	return
}

// GetClassmatesById retrieves Classmates by Id. Returns error if
// Id doesn't exist
func GetClassmatesById(id int) (v *Classmates, err error) {
	o := orm.NewOrm()
	v = &Classmates{Id: id}
	if err = o.Read(v); err == nil {
		return v, nil
	}
	return nil, err
}

// GetAllClassmates retrieves all Classmates matches certain condition. Returns empty list if
// no records exist
func GetAllClassmates(query map[string]string, fields []string, sortby []string, order []string,
	offset int64, limit int64) (ml []interface{}, err error) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(Classmates))
	// query k=v
	for k, v := range query {
		// rewrite dot-notation to Object__Attribute
		k = strings.Replace(k, ".", "__", -1)
		if strings.Contains(k, "isnull") {
			qs = qs.Filter(k, (v == "true" || v == "1"))
		} else {
			qs = qs.Filter(k, v)
		}
	}
	// order by:
	var sortFields []string
	if len(sortby) != 0 {
		if len(sortby) == len(order) {
			// 1) for each sort field, there is an associated order
			for i, v := range sortby {
				orderby := ""
				if order[i] == "desc" {
					orderby = "-" + v
				} else if order[i] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
			qs = qs.OrderBy(sortFields...)
		} else if len(sortby) != len(order) && len(order) == 1 {
			// 2) there is exactly one order, all the sorted fields will be sorted by this order
			for _, v := range sortby {
				orderby := ""
				if order[0] == "desc" {
					orderby = "-" + v
				} else if order[0] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
		} else if len(sortby) != len(order) && len(order) != 1 {
			return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
		}
	} else {
		if len(order) != 0 {
			return nil, errors.New("Error: unused 'order' fields")
		}
	}

	var l []Classmates
	qs = qs.OrderBy(sortFields...)
	if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
		if len(fields) == 0 {
			for _, v := range l {
				ml = append(ml, v)
			}
		} else {
			// trim unused fields
			for _, v := range l {
				m := make(map[string]interface{})
				val := reflect.ValueOf(v)
				for _, fname := range fields {
					m[fname] = val.FieldByName(fname).Interface()
				}
				ml = append(ml, m)
			}
		}
		return ml, nil
	}
	return nil, err
}

// UpdateClassmates updates Classmates by Id and returns error if
// the record to be updated doesn't exist
func UpdateClassmatesById(m *Classmates) (err error) {
	o := orm.NewOrm()
	v := Classmates{Id: m.Id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Update(m); err == nil {
			fmt.Println("Number of records updated in database:", num)
		}
	}
	return
}

// DeleteClassmates deletes Classmates by Id and returns error if
// the record to be deleted doesn't exist
func DeleteClassmates(id int) (err error) {
	o := orm.NewOrm()
	v := Classmates{Id: id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Delete(&Classmates{Id: id}); err == nil {
			fmt.Println("Number of records deleted in database:", num)
		}
	}
	return
}

func Login(sn, pswd string) *Classmates {

	var user Classmates
	// 改为从redis查。
	conn := redisPool.Get()
	studentValues, err := redis.StringMap(conn.Do("hgetall", sn))
	if err != nil {
		return nil
	}
	if studentValues["pswd"] == pswd {
		user.Name = studentValues["name"]
		user.Sex = studentValues["sex"]
		user.Pswd = studentValues["pswd"]
		user.Tel = studentValues["tel"]
		user.Email = studentValues["email"]
		user.Face = studentValues["face"]
		user.Id, _ = strconv.Atoi(studentValues["id"])
		return &user
	}
	return nil

}

// 提前将mysql数据库中的所有学生数据  导入到redis中。方便后续使用
func ImportAllStudentsToRedis() bool {
	o := orm.NewOrm()
	var allStudents []*Classmates
	_, err := o.QueryTable("classmates").All(&allStudents)
	if err != nil {
		fmt.Println("导入学生资料到redis的时候  出错了：", err.Error())
		return false
	}
	conn := redisPool.Get()
	for _, student := range allStudents {
		conn.Do("hset", student.Sn, "name", student.Name)
		conn.Do("hset", student.Sn, "sn", student.Sn)
		conn.Do("hset", student.Sn, "pswd", student.Pswd)
		conn.Do("hset", student.Sn, "id", student.Id)
		conn.Do("hset", student.Sn, "sex", student.Sex)
		conn.Do("hset", student.Sn, "account", student.Account)
		conn.Do("hset", student.Sn, "tel", student.Tel)
		conn.Do("hset", student.Sn, "email", student.Email)
		conn.Do("hset", student.Sn, "face", student.Face)
	}
	return true
}

func ModifyInfo(id int, info *Classmates) bool {
	o := orm.NewOrm()
	v := Classmates{Id: id}
	err := o.Read(&v)
	if err != nil {
		return false
	}
	info.Id = id
	_, err = o.Update(info)
	if err != nil {
		return false
	}
	return true

}

func ModifyPsed(id int, oldpswd, newpswd string) bool {
	o := orm.NewOrm()

	v := Classmates{Id: id}
	err := o.Read(&v)
	if err != nil {
		return false
	}
	if v.Pswd != oldpswd {
		return false
	}
	v.Pswd = newpswd
	_, err = o.Update(&v, "Pswd")
	if err != nil {
		return false
	}
	return true

}

func Zhuanzhang(sendid, receiverid int, edu float64) (string, time.Time, bool) {
	o := orm.NewOrm()

	sender := Classmates{Id: sendid}
	err := o.Read(&sender)
	if err != nil {
		return err.Error(), time.Now(), false
	}

	receiver := Classmates{Id: receiverid}
	err = o.Read(&receiver)
	if err != nil {
		return err.Error(), time.Now(), false
	}
	sender.Account = sender.Account - edu
	if sender.Account < 0 {
		return "你的账户没那么多钱了哥们", time.Now(), false
	}
	receiver.Account = receiver.Account + edu
	_, err = o.Update(&sender, "Account")
	if err != nil {
		return err.Error(), time.Now(), false
	}
	_, err = o.Update(&receiver, "Account")
	if err != nil {
		return err.Error(), time.Now(), false
	}
	return "", time.Now(), true
}

const (
	// jwt 加密秘钥
	JwtMiyao = "%￥……&*（）IYUFGHVHJKLHFTYUIOJHKBGHyuio%^&*()UTYDFGCHVJKI*(&TYUGHJ)"
)

// GetJwtString GetJwtString
func GetJwtString(expire int, name, sn string, id int, role int8) (string, error) {
	token := jwt.New(jwt.SigningMethodHS256)
	claims := make(jwt.MapClaims)
	now := time.Now()
	claims["exp"] = now.Add(time.Hour * time.Duration(expire)).Unix()
	claims["id"] = id
	claims["r"] = role
	claims["sn"] = sn
	claims["name"] = name
	token.Claims = claims
	tokenString, err := token.SignedString([]byte(JwtMiyao))
	return tokenString, err
}

func SetUserFace(userid, face string) bool {
	o := orm.NewOrm()
	sql := fmt.Sprintf("UPDATE `chuanyou`.`classmates` SET `face` = '%s' WHERE (`id` =  %v);", face, userid)

	_, err := o.Raw(sql).Exec()
	if err != nil {
		return false
	}

	return true

}

type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}
type RequestBody struct {
	Model    string    `json:"model"`
	Messages []Message `json:"messages"`
}

type Choice struct {
	FinishReason string  `json:"finish_reason"`
	Messages     Message `json:"message"`
}

type ResposeBody struct {
	Model   string   `json:"model"`
	Choices []Choice `json:"choices"`
}

// 调用阿里云ai的函数。
func CallAliyunAi(question string) string {
	// 创建 HTTP 客户端
	client := &http.Client{}
	// 构建请求体
	requestBody := RequestBody{
		// 模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
		Model: "qwen-plus",
		Messages: []Message{
			{
				Role:    "system",
				Content: "You are a helpful assistant.",
			},
			{
				Role:    "user",
				Content: question,
			},
		},
	}
	jsonData, err := json.Marshal(requestBody)
	if err != nil {

		return ""
	}
	// 创建 POST 请求
	req, err := http.NewRequest("POST", "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions", bytes.NewBuffer(jsonData))
	if err != nil {
		return ""
	}
	// 设置请求头
	// 若没有配置环境变量，请用百炼API Key将下行替换为：apiKey := "sk-xxx"
	req.Header.Set("Authorization", "Bearer "+aliyunKey)
	req.Header.Set("Content-Type", "application/json")
	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		return ""
	}
	defer resp.Body.Close()
	// 读取响应体
	bodyText, err := io.ReadAll(resp.Body)
	if err != nil {
		return ""
	}
	//返回输出

	var result ResposeBody
	err = json.Unmarshal(bodyText, &result)
	if err != nil {
		return ""
	}
	return result.Choices[0].Messages.Content
}

func Xieruzhe(tongdao chan int, start, end int) {
	for i := start; i < end; i++ {
		tongdao <- i
		time.Sleep(time.Second)
	}
}

func QiuHe(tongdao chan int, start, end int) {
	var result int
	for i := start; i < end; i++ {
		result = result + i
	}
	tongdao <- result
}
